﻿//// The code in this file was written by Vincent R. Johns, who has
//// placed it into the public domain but makes no guarantee that it
//// will perform as expected or desired.
//// Anyone may copy or modify any part of it without charge or obligation.
//// Quick-start instructions and examples are near the end of this file.

////If CallMainEntryPoint is defined, Main() in the
////  module under development is called as if
////  its class were the startup object.
////If CallMainEntryPoint is undefined, the TDS test methods
////  are run without calling Main() in the code module 
////  under development.
////This symbol has an effect only if the
////  project's startup object is TDS.Test{} .
//#define CallMainEntryPoint  //This symbol is defined only in this source file.

////If defined, RunOnlySelectedTestData enables "#if" statements
////  in the test methods that may skip some of the test data.
////  This could be used to select a specific test case for 
////  detailed debug tracing, skipping immaterial cases.
//#define RunOnlySelectedTestData  //This symbol may also be defined in other source files in this project.

////If this is defined, the elements of testValues[] in the example
////  TestableConsoleMethodTest() method are defined via
////  the TestableConsoleMethodTestCase{} class
////  instead of via an anonymous object type.
////The example code should function identically in either case.
//#define UseNamedObjectTypeInTestableConsoleMethodTest  //This symbol is defined only in this source file.

#if(RunOnlySelectedTestData)
#warning Only selected tests will be run, because RunOnlySelectedTestData is defined in file TDS.cs .
#endif //RunOnlySelectedTestData

using NUnit.Core;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
//TODO: Include "using" statements for the namespaces of the code being developed.
//using ConsoleApplication1;  //TODO: Replace or de-comment this statement

namespace TDS
{

#if(DEBUG)

  #region NUnit Attributes
  //The following statements allow the attribute names
  //    belonging to Visual Studio tests to be used with NUnit tests.
  //    Either version should function similarly, but the
  //    Microsoft.VisualStudio.TestTools.UnitTesting attribute names,
  //    such as [ClassInitialize], are the versions used in this file.

  /// <summary>
  /// <para><c>[ClassCleanup]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  /// identifies a method that contains code to be used
  /// after all the tests in the test class have run
  /// and to free resources obtained by the test class.</para>
  /// <para>This is redirected to <c>[TestFixtureTearDown]</c> in NUnit.
  /// <c>[TestFixtureTearDown]</c> is used inside a <c>[TestFixture]</c>
  /// to provide a single set of functions that are performed once
  /// after all tests are completed. </para>
  /// </summary>
  public class ClassCleanupAttribute : TestFixtureTearDownAttribute { }

  /// <summary>
  /// <para><c>[ClassInitialize]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  /// identifies a method that contains code that must be used
  /// before any of the tests in the test class have run
  /// and to allocate resources to be used by the test class.</para>
  /// <para>This is redirected to <c>[TestFixtureSetUp]</c> in NUnit; 
  /// <c>[TestFixtureSetUp]</c> is used inside a <c>[TestFixture]</c>
  /// to provide a single set of functions that are performed once 
  /// prior to executing any of the tests in the fixture. </para>
  /// </summary>
  public class ClassInitializeAttribute : TestFixtureSetUpAttribute { }

  /// <summary>
  /// <para><c>[TestClass]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  /// is used to identify classes that contain test methods.</para>
  /// <para>This is redirected to <c>[TestFixture]</c> in NUnit; 
  /// <c>[TestFixture]</c> marks a class that contains tests and, optionally, setup or teardown methods. 
  /// </para>
  /// </summary>
  public class TestClassAttribute : TestFixtureAttribute { }

  /// <summary>
  /// <para><c>[TestCleanup]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  /// identifies a method that contains code that must be used
  /// after the test has run and to free resources
  /// obtained by all the tests in the test class.</para>
  /// <para>This is redirected to <c>[TearDown]</c> in NUnit; 
  /// this attribute is used inside a <c>[TestFixture]</c>
  /// to provide a common set of functions
  /// that are performed after each test method is run.</para>
  /// </summary>
  public class TestCleanupAttribute : TearDownAttribute { }

  /// <summary>
  /// <para><c>[TestInitialize]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  /// identifies the method to run before the test
  /// to allocate and configure resources needed
  /// by all tests in the test class.</para>
  /// <para>This is redirected to <c>[SetUp]</c> in NUnit; 
  /// this attribute is used inside a <c>[TestFixture]</c>
  /// to provide a common set of functions that are performed
  /// just before each test method is called.</para>
  /// </summary>
  public class TestInitializeAttribute : SetUpAttribute { }

  /// <summary>
  /// <para><c>[TestMethod]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  /// is used to identify test methods.</para>
  /// <para>This is redirected to <c>[Test]</c> in NUnit; 
  /// <c>[Test]</c> marks a method inside
  /// a <c>[TestFixture]</c> class as a test.
  /// </para>
  /// </summary>
  public class TestMethodAttribute : TestAttribute { }

  //******  Others  *******//
  //The following attributes have the same name in both systems,
  // though their behavior may not be identical:
  #region Same-named attributes
  ///// <summary>
  ///// <para><c>[ExpectedException]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  ///// indicates that an exception is expected during test method execution.</para>
  ///// <para><c>[ExpectedException]</c> in NUnit 
  ///// is the way to specify that the execution of a test
  ///// will throw an exception.</para>
  ///// </summary>
  //public class ExpectedExceptionAttribute : ExpectedExceptionAttribute { }

  ///// <summary>
  ///// <para><c>[Ignore]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  ///// indicates that a specific test should not be run.</para>
  ///// <para><c>[Ignore]</c> in NUnit 
  ///// is an attribute to not run a test or test fixture
  ///// for a period of time.</para>
  ///// </summary>
  //public class IgnoreAttribute : IgnoreAttribute { }

  ///// <summary>
  ///// <para><c>[Timeout]</c> in Microsoft.VisualStudio.TestTools.UnitTesting
  ///// is used to specify the time-out period of a unit test.</para>
  ///// <para><c>[Timeout]</c> in NUnit 
  ///// is used to specify a timeout value in milliseconds
  ///// for a test case.</para>
  ///// </summary>
  //public class TimeoutAttribute : TimeoutAttribute { }
  #endregion Same-named attributes

  #endregion NUnit Attributes

  /// <summary>
  /// This class is intended to contain
  /// "Test-Driven Scaffolding" ("TDS") drivers
  /// used in developing methods for another class.
  /// </summary>
  /// <remarks>
  /// The source file initially contains the following templates
  /// (example drivers for new methods):
  /// <para>
  /// <see cref="TestableConsoleMethodTest()"/> is an example test method
  /// for <see cref="TestableConsoleMethod()"/>,
  /// a method that uses the Console.</para>
  /// <para>
  /// <see cref="TestableNoConsoleMethodTest()"/> is an example test method
  /// for <see cref="TestableNoConsoleMethod()"/>,
  /// a method that does not use the Console.</para>
  /// <para>These may be used as a basis for developing your own
  /// Test Driven Scaffolding (TDS) drivers.</para>
  /// <para>In their present form, these templates may be used
  /// as unit tests for the example methods that accompany them,
  /// to demonstrate that the unit test system is operating properly,
  /// but their real purpose is to be copied
  /// and modified to use as drivers for new methods under development.</para>
  /// <para>After the definition of a new method is sufficiently complete,
  /// its TDS method can be easily modified
  /// to become a unit-test method usable by NUnit
  /// or by Visual Studio's VisualStudio.TestTools.UnitTesting facilities.</para>
  /// </remarks>
  [TestClass]
  public static partial class Test
  {

    /// <summary>
    /// Message used to indicate that no exception 
    /// was thrown by a called method
    /// </summary>
    const string DefaultExceptionMessage = " No exception was thrown";

    /// <summary>
    /// True iff the TDS methods are being run via a call
    /// to <see cref="TDS.Test.RunTdsTests"/>(),
    /// false if they are being run using a unit-test system
    /// (such as NUnit or the Visual Studio test facility).
    /// <para>This specifies if the TDS methods are running 
    /// independently of a unit-test system, such as NUnit.
    /// This is used within TDS methods
    /// to govern explicit calls to methods marked
    /// with attributes such as [TestInitialize] and [TestCleanup],
    /// that the unit-test facility would run automatically.</para>
    /// </summary>
    /// <remarks><para>This allows the explicit calls to methods such as
    /// <see cref="InitializeTestMethod"/>() to be bypassed by the unit-test system,
    /// which utilizes atttributes such as <c>[TestInitialize]</c> instead.</para>
    /// </remarks>
    static bool IsUsingStandAloneTds = false;

    /// <summary>
    /// True iff some test cases (sets of values for
    /// initialization and comparison)
    /// within each test method in this source file
    /// may be skipped during the test run.
    /// <para>For example, a calling program might utilize this
    /// to decide to issue a warning message
    /// that not all cases are being tested.</para> 
    /// </summary>
    /// <remarks>
    /// <para>Each source file in this namespace
    /// should define a field similar to this,
    /// to be used by <see cref="AreAnyTestCasesSkipped()"/> .</para>
    /// <para>This constant makes the conditional compilation symbol
    /// <c>RunOnlySelectedTestData</c> visible outside this source file.</para>
    /// </remarks>
    public const bool OnlySelectedTestDataAreUsed =
#if (RunOnlySelectedTestData)
 true;
#else
 false;
#endif //(RunOnlySelectedTestData)

    /// <summary>
    /// Message about missing (or misspelled) file suffix or
    /// OnlySelectedTestDataAreUsed symbol.
    /// <para>{0} = symbol name</para>
    /// <para>{1} = file name</para>
    /// <para>Example, with {0} = "OnlySelectedTestDataAreUsed_Ex01" and {1} = "TDS_Ex01.cs":</para>
    /// <para>Symbol "OnlySelectedTestDataAreUsed_Ex01" is apparently not defined;</para>
    /// <para>it should be defined in file TDS_Ex01.cs .</para>
    /// <para>File TDS_Ex01.cs may be missing or be malformed in some way;</para>
    /// <para>for example, TDS_Ex01.cs might be present in the project but not contain</para>
    /// <para>the required "public static partial class Test" declaration.</para>
    /// </summary>
    internal const string MissingSymbolMsg = @"
Symbol ""{0}"" is apparently not defined;
    it should be defined in file {1} .
File {1} may be missing or be malformed in some way;
    for example, {1} might be present in the project but not contain
    the required ""public static partial class Test"" declaration.";

    /// <summary>
    /// Status resulting from running a test.
    /// <para>Reported results follow the order implied here, with
    /// the list of <see cref="Passed"/> tests appearing first.</para>
    /// </summary>
    internal enum RunStatus : int
    {
      /// <summary>
      /// Test method did not raise an exception
      /// </summary>
      Passed,
      /// <summary>
      /// Test method raised an exception other than Inconclusive
      /// </summary>
      Failed,
      /// <summary>
      /// Test method raised an InconclusiveException exception
      /// </summary>
      Inconclusive,
      /// <summary>
      /// Highest value in the list
      /// </summary>
      Max = Inconclusive
    }  // end:RunStatus enum

    /// <summary>
    /// Message warning about possible omitted test cases.
    /// <para>{0} = comma-separated list of file names</para>
    /// <para>Example, with {0} = "TDS.cs":</para>
    /// <para>*** Some test cases may have been skipped! ***</para>
    /// <para>To run all test cases in the test methods that are called,</para>
    /// <para>comment out "#define RunOnlySelectedTestData" directives in the</para>
    /// <para>following file(s):</para>
    /// <para>TDS.cs</para>
    /// </summary>
    internal const string SkippedTestsMsg = @"
       *** Some test cases may have been skipped! ***

           To run all test cases in the test methods that are called,
           comment out ""#define RunOnlySelectedTestData"" directives in the
           following file(s):
             {0}
";

    /// <summary>
    /// List of all <c>TDS*.cs</c> or similar source files in the project,
    /// for use in identifying active 
    /// "#define RunOnlySelectedTestData" directives.
    /// </summary>
    /// <remarks>
    /// TODO: Be sure that all TDS source files that might utilize "#define RunOnlySelectedTestData" are included in this list.
    /// </remarks>
    internal static string[] TestMethodsSourceFiles = new[] {
      "",  //for TDS.cs
      "Ex01",  //for TDS_Ex01.cs
    };

    /// <summary>
    /// This contains a list of TDS test methods in the TDS namespace
    /// to be run via <see cref="RunTdsTests"/>(); 
    /// tests will be run in the order in which they appear here.
    /// <para>Test methods listed here should be <c>public</c>
    /// or <c>internal</c>, return <c>void</c>, and take no parameters,
    /// but they need not have a [TestMethod] attribute.
    /// No automatic check is provided that all test methods
    /// in the namespace are included in this list; it will 
    /// typically identify only the TDS test methods that
    /// exercise code under active development.
    /// After your code is largely complete, each TDS method can
    /// be converted to a test method usable by NUnit or a similar
    /// unit-test support system and removed from this list.</para>
    /// </summary>
    /// <remarks>
    /// <para>Its initial contents are references to the three example
    /// TDS test methods supplied with this file, and these should be replaced
    /// with references to your own test methods.</para>
    /// <para>You may find it convenient to place a list here
    /// of all of your currently active TDS test methods,
    /// and selectively comment out those that you do not wish to run now.
    /// (The results will be similar to selecting or clearing
    /// check boxes in the NUnit GUI.)</para>
    /// </remarks>
    internal static Action[] TestMethodsToBeRun = new Action[] { 
              AllTestsAreToBeRunTest, 
              TestableConsoleMethodTest, 
              TestableNoConsoleMethodTest,
              ////TODO: Include in this list all of the TDS tests that you wish to run.
            };

    /// <summary>
    /// String included at the beginning of each trace message,
    /// currently "***** " .
    /// </summary>
    /// <remarks><para>This can help identify messages in the Console output
    /// that indicate that constructors (for example) have run.</para>
    /// <para>Since each such message contains this string,
    /// all of these messages can be easily located if you wish to remove them.</para>
    /// <para>One exception occurs in the #if (Code_to_be_copied) region, in the
    /// example static constructor for the <c>Program{}</c> class,
    /// where the literal value "***** " is used instead of the name <c>TraceFlag</c>,
    /// to avoid making an unwanted reference to TDS.</para>
    /// </remarks>
    public const string TraceFlag = "***** ";

    /// <summary>
    /// Test to verify that conditional compilation symbol <see cref="RunOnlySelectedTestData"/> is disabled in all TDS source files.
    /// <para><see cref="RunOnlySelectedTestData"/> may be defined to allow test methods to run only selected test cases,
    /// for example to facilitate debugging the test methods or the program methods that are being tested,
    /// but it is likely to mislead the test system (NUnit or Visual Studio)
    /// into indicating that some tests are succeeding that should actually fail.</para>
    /// </summary>
    [TestMethod]
    public static void AllTestsAreToBeRunTest()
    {
      try
      {
        if (IsUsingStandAloneTds) InitializeTestMethod();

        string fileList = AreAnyTestCasesSkipped();

        Assert.IsTrue(fileList == "",
              String.Format(SkippedTestsMsg
                  , fileList //{0}
              ));
      }
      finally
      {
        if (IsUsingStandAloneTds) CleanupTestMethod();
      }
    }  // end:AllTestsAreToBeRunTest()

    /// <summary>
    /// <para>
    /// Determines if conditional compilation symbol <see cref="RunOnlySelectedTestData"/>
    /// is disabled in all TDS source files
    /// (which should all be listed in <see cref="TestMethodsSourceFiles"/>).</para>
    /// <para>Each TDS source file should contain a public constant
    /// similar to <see cref="TDS.Test.OnlySelectedTestDataAreUsed"/>
    /// that identifies if a <c>#define RunOnlySelectedTestData</c> directive
    /// is active in that file.</para>
    ///</summary>
    ///<remarks>
    /// <para>A <c>#define RunOnlySelectedTestData</c> directive 
    /// may be used to allow test methods to run only selected test cases,
    /// for example to facilitate debugging code that is under development,
    /// by specifying that only the data that will exercise a specific part
    /// of the code should be run.
    /// However, leaving <c>RunOnlySelectedTestData</c> defined when it is not needed
    /// is likely to mislead the test system (NUnit or Visual Studio)
    /// into indicating that some tests are succeeding that should actually fail.</para>
    /// <para><see cref="AreAnyTestCasesSkipped"/> is designed to always return
    /// a list of file names
    /// whenever <see cref="RunOnlySelectedTestData"/> is defined
    /// in any of the listed files,
    /// to avoid accidentally leaving it defined when it should not be.</para>
    ///</remarks>
    ///<returns>Comma-delimited list of names of all files containing
    ///an active <c>#define RunOnlySelectedTestData</c> directive.
    /// If no source files contain that, the returned value is an empty string.
    ///</returns>
    public static string AreAnyTestCasesSkipped()
    {
      //Main part of the name of each file's field containing the
      //  state of the file's "RunOnlySelectedTestData" symbol
      const string SelectedDataSymbol = "OnlySelectedTestDataAreUsed";

      //Beginning of the name of each source-code file in the TDS namespace
      const string filePrefix = "TDS";

      //Comma-separated list of source files that might contain
      //    a "#define RunOnlySelectedTestData" directive to
      //    run only some of their test cases.
      var listedFiles = "";

      foreach (var fName in TestMethodsSourceFiles)
      {
        //If field fieldN defined in source file fileName is true, 
        //    append the fileName name (and comma) to listedFiles
        var fileSuffix = (fName == "" ? "" : "_") + fName;  //Example: "_Ex01"
        var fieldN = SelectedDataSymbol + fileSuffix;  //Example: "OnlySelectedTestDataAreUsed_Ex01"
        var fileName = filePrefix + fileSuffix + ".cs";  //Example: "TDS_Ex01.cs"
        try
        {
          //If (for example) field
          //    OnlySelectedTestDataAreUsed_Ex01,
          //    which should be defined in source file TDS_Ex01.cs,
          //    is true, append the "TDS_Ex01.cs" file name to listedFiles
          //    and render allOK false.
          //  Otherwise, do nothing.
          if ((bool)(typeof(Test).GetField(fieldN).GetValue(null)))  //True iff only a subset of the test cases are to be run
          {
            listedFiles += fileName + ", ";    //Name of source file containing the selected field
          }
        }
        catch (NullReferenceException)
        {
          throw new ApplicationException(
                String.Format(MissingSymbolMsg
                  , fieldN  //{0}
                  , fileName  //{1}
                ));
        }
      }

      return listedFiles == ""
            ? ""
            : listedFiles.Substring(0, listedFiles.Length - 2);  //Erase the final comma
    }  // end:AreAnyTestCasesSkipped()

    /// <summary>
    /// <para>This is intended to be run after, or at the end of,
    /// each <c>[TestMethod]</c> method, to finalize the code being tested.</para>
    /// <para>It writes a message to the Console (visible on the test report),
    /// but, for ease of maintenance, any other code needed at the
    /// end of each test should also be located here.</para>
    /// </summary>
    [TestCleanup]
    public static void CleanupTestMethod()
    {

      //TODO: Add other test-cleanup code here

      Console.WriteLine(TraceFlag + "CleanupTestMethod() is complete."
            + "\r\n" + TraceFlag + "(End of test)"
            + "\r\n");
    }  // end:CleanupTestMethod()

    /// <summary>
    /// <para>This is intended to be run after
    /// the last <c>[TestMethod]</c> method is complete,
    /// to finalize the code being tested.</para>
    /// <para>It writes a message to the Console (visible on the test report),
    /// but, for ease of maintenance, 
    /// any other code needed to be run after the final test
    /// should also be located here.</para>
    /// </summary>
    [ClassCleanup]
    public static void CleanupTestSession()
    {

      //TODO: Add other end-of-session code here


      Console.WriteLine(@"
{0}The final test was completed at {1} .
{0}CleanupTestSession() is complete.
"
            , TraceFlag  //{0} 
            , DateTime.Now  //{1} 
            );

    }  // end:CleanupTestSession()

    /// <summary>
    /// This calls the classes under test,
    /// so that they can be initialized
    /// (for example, ensuring that each class's
    /// static constructor has been run to completion)
    /// before any test procedures are run.
    /// </summary>
    /// <remarks>
    /// <para>If a unit test system, such as
    /// NUnit or Visual Studio Test, is being used, 
    /// and the <c>[ClassInitialize]</c> attribute is present,
    /// that system will call <see cref="InitializeClasses"/>()
    /// once before running any of the test methods,
    /// so all necessary initialization is complete by the time
    /// any test method is called.</para>
    /// <para>The reference to the static field
    /// <see cref="isInitialized"/> in each listed class
    /// is present only for the purpose of calling
    /// the class's static constructor.
    /// The intent is that this reference will set up
    /// any <c>static</c> fields referred to by the test methods,
    /// but using a reference to any other accessible <c>static</c> field or property,
    /// instead of to <see cref="isInitialized"/>, would accomplish the same purpose,
    /// and the definition of <see cref="isInitialized"/> could then be deleted
    /// without affecting <see cref="InitializeClasses"/>() .</para>
    /// </remarks>
    [ClassInitialize]
    public static void InitializeClasses()
    {

      //Display version number
      var assm = Assembly.GetExecutingAssembly().GetName();

      Console.WriteLine(
@"{0}InitializeClasses() has begun running
        in assembly {1}, version {2} ."
            , TraceFlag  //{0} 
            , assm.Name  //{1} 
            , assm.Version  //{2} 
            );
      
      //This Action is used to make it easy to standardize all
      //  of the messages reporting on active conditions.
      Action <string> ReportSymbol = symbolName =>
            Console.WriteLine(
@"{0}Conditional compilation symbol
        {1} is defined."
                  , TraceFlag  //{0} 
                  , symbolName  //{1} 
                  );

      //TODO: Also include in this list any other conditional compilation symbols
      //      (except DEBUG and RunOnlySelectedTestData, whose states are reported elsewhere)
#if(CallMainEntryPoint)
      ReportSymbol("CallMainEntryPoint");
#endif //(CallMainEntryPoint)
#if(UseNamedObjectTypeInTestableConsoleMethodTest)
      ReportSymbol("UseNamedObjectTypeInTestableConsoleMethodTest");
#endif //(UseNamedObjectTypeInTestableConsoleMethodTest)

      ////  Edit the following "if()" statement to include Boolean expressions
      ////    that refer to some public static field or property
      ////    of each closed class to be tested, to ensure that
      ////    that class's static constructor, if any, has been run.
      ////    Separate the expressions with single "|" or "&" operators,
      ////    to ensure that all of them are utilized.
      ////  This example initializes Program{}, but a similar statement 
      ////    needs to be added for every other class being tested as well.
      if (true

#if (!CallMainEntryPoint)
        //If Main() of the module under development is called, the
        //  module's static constructor will already have been called
        //  without depending on this expression, making this
        //  expression unnecessary.
        //Also, if TDS.Test{} is not the startup object,
        //  use of this expression could lead to a circular dependency.
        | ConsoleApplication1.Program.isInitialized  //Rename this if necessary to refer to an existing variable
#endif //(!CallMainEntryPoint)

        ////TODO: Include a reference to some variable in each testable class in this assembly.


      ) { }  //This statement block is intentionally empty.

      //TODO: Add other class-setup code here

    }  // end:InitializeClasses()

    /// <summary>
    /// <para>This is intended to be run before, or at the beginning of,
    /// each <c>[TestMethod]</c> method, to initialize the code being tested.</para>
    /// <para>It calls <see cref="InitializeClasses"/>() and writes
    /// a message to the Console (visible on the test report),
    /// but, for ease of maintenance, any other code needed at the
    /// beginning of each test should also be located here.</para>
    /// </summary>
    /// <remarks>In standalone mode 
    /// (<see cref="IsUsingStandAloneTds"/> is true),
    /// <see cref="InitializeClasses"/>() has already
    /// been called by the static constructor, before this runs.</remarks>
    [TestInitialize]
    public static void InitializeTestMethod()
    {

      Console.WriteLine(TraceFlag + "InitializeTestMethod() has been called.");

      //TODO: Add other test-setup code here

    }  // end:InitializeTestMethod()

    /// <summary>
    /// This is the entry point if the module is a stand-alone file.
    /// </summary>
    /// <remarks>This is used only if the project's startup object
    /// is set to <see cref="TDS.Test"/>{} .</remarks>
    static void Main()
    {
#if (CallMainEntryPoint)
      // Call Main() of the developing code, as if TDS were not present
      ConsoleApplication1.Program.Main(new[] { "" });
#else  //if (!CallMainEntryPoint)
      // Run TDS test methods directly, without invoking Main()
      RunTdsTests();
#endif //(!CallMainEntryPoint)
    }  // end:Main()

    /// <summary>
    /// Run the TDS test methods listed in <see cref="TestMethodsToBeRun"/>[] .
    /// <para>This may be called from Main(), 
    /// or a static constructor, or some other suitable location,
    /// following the execution of all code that initializes any variables
    /// used by the code to be tested.</para>
    /// <para>Although all of the TDS test methods should be
    /// <c>public</c> methods that return <c>void</c>
    /// and take no parameters, they can test any accessible code
    /// that implements a function member of a class or struct.
    /// (The code being developed might need to have its accessibility
    /// temporarily changed to <c>public</c> or <c>internal</c> 
    /// to allow it to be invoked by the TDS test method.)
    /// </para>
    /// <para>TDS is intended to be used as an aid to development,
    /// not as a comprehensive testing system.
    /// If you wish to use testing features that are not included
    /// in the TDS templates, such as timeout detection,
    /// you may either write code in your TDS methods to provide these,
    /// or delay using them until after you have converted
    /// your TDS code to tests run under a unit-test system such as NUnit.</para>
    /// </summary>
    /// <remarks>
    /// <para>The text written to the Console mimics that which should appear
    /// on NUnit's "Text Output" window, followed by a report of which of the
    /// tested methods passed, failed, or were inconclusive, along with
    /// the text of exceptions that they generated.</para>
    /// <para>Although initialization code such as <see cref="InitializeClasses"/>()
    /// is run by both the TDS methods and a unit-test system such as NUnit,
    /// actions performed by <c>Main()</c> before the call to
    /// <see cref="RunTdsTests"/>() might be invisible to NUnit
    /// and could give rise to differing results.
    /// Placing this call as early as possible following initialization
    /// may help to minimize such differences.</para>
    /// <para>Instead of maintaining the list of TDS test methods
    /// in the field <see cref="TestMethodsToBeRun"/>,
    /// you may find it more convenient to pass this list
    /// as a parameter to <see cref="RunTdsTests"/>(),
    /// making it easier to see which tests are being called,
    /// though perhaps also making <see cref="Main"/>() more
    /// cluttered and difficult to read.</para>
    /// </remarks>
    public static void RunTdsTests()
    {
      //This method is not expected to be used in an NUnit run
      IsUsingStandAloneTds = true;

      var returnedPhrase = "returned a status of ";

      InitializeClasses();

      //Line written to separate parts of the status report
      var separator = @"________________";

      var testStatusList = new List<Tuple<RunStatus, string, Exception>>();
      var totals = new Dictionary<RunStatus, int>((int)RunStatus.Max + 1);

      //Run each listed test method and collect a list of the results,
      //    to include status and the text of exception messages.
      //Messages written to the Console will mimic those displayed
      //    in NUnit's "Text Output" window.
      foreach (var method in TestMethodsToBeRun)
        testStatusList.Add(RunTestMethod(method));

      CleanupTestSession();

      //The following messages contain information about the results of tests.
      //Some of the included information is similar to messages that might
      //    appear in NUnit's "Errors and Failures" window, but the format
      //    is not similar.
      Console.WriteLine(@"
{0}
{1} This was a test run.  The following results were generated. {1}"
              , separator  //{0}
              , TraceFlag  //{1}
            );

      //Display the lists of tests and results
      for (var status = (RunStatus)0;
            status <= RunStatus.Max; status++)
      {
        //List of names of test methods returning this status
        //  ListPage[].Name = method name
        //  ListPage[].ExMsg = "Assert" exception message text
        var listPage =
              from s in testStatusList
              where s.Item1 == status
              select new {
                //Method name
                Name = s.Item2,
                //"Assert" exception message text
                ExMsg = s.Item3 == null
                  ? ""
                  : s.Item3.Message
              };

        var listCount = listPage.Count();

        totals.Add(status, listCount);

        if (listCount == 0)
          //Example:
          //No called test method returned a status of Failed.
          Console.WriteLine(@"
{0}
No called test method {1}{2}."
                , separator  //{0}
                , returnedPhrase  //{1}
                , status  //{2}
                );
        else
        {
          //Example:
          //Failed tests
          //  The following 3 test methods returned a status of Failed:
          Console.WriteLine(@"
{0}
{4} tests
  The following {1}test method{2} {3}{4}:"
                , separator  //{0}
                , listCount <= 1 ? "" : listCount + " "  //{1}
                , listCount <= 1 ? "" : "s"  //{2}
                , returnedPhrase  //{3}
                , status  //{4}
                );

          foreach (var reportItem in
                 listPage)
          {
            if (status != RunStatus.Passed)
              //There are no comments on Passed tests, so no need to separate their reports
              Console.WriteLine();

            Console.WriteLine("  - {0}"
                    , reportItem.Name  //{0}
                  );
            if (reportItem.ExMsg != "")
              Console.WriteLine(@"      Exception message:
{0}"
                      , reportItem.ExMsg  //{0}
                    );
          }
        }
      }

      Console.WriteLine(@"
{0}"
            , separator  //{0}
            );

      //Write a summary, as in this example:
      //Passed: 1  Failed: 0  Inconclusive: 2
      for (var status = (RunStatus)0; status <= RunStatus.Max; status++)
      {
        Console.Write("{0}: {1}  "
          , status  //{0}
          , totals[status]  //{1}
          );
      }
      Console.WriteLine();
      Console.WriteLine();

      string fileList;

      if (totals[RunStatus.Passed] > 0
            && totals[RunStatus.Failed] == 0
            && totals[RunStatus.Inconclusive] == 0)
      {
        Console.WriteLine("All test methods that were called passed.");

        fileList = AreAnyTestCasesSkipped();
        if (fileList != "")
          Console.WriteLine(SkippedTestsMsg
                  , fileList //{0}
                );
        else
          Console.WriteLine(@"
       All test cases in each test method were run.");

      }

      var assm = Assembly.GetExecutingAssembly().GetName();

      Console.WriteLine(@"
{0}The final test of {1}, version {2} ,
      was completed at {3} .
{0}CleanupTestSession() is complete.
{0}(End of test summary)
"
            , TraceFlag  //{0} 
            , assm.Name  //{1} 
            , assm.Version  //{2} 
            , DateTime.Now  //{3} 
            );

      Console.Write(@"
Press the space bar to continue . . .");

      Console.ReadKey(false);  //Wait for user to press a key.
      Console.WriteLine();  //Put the default "Press any key..." message, if any, onto a new line

    }  // end:RunTdsTests()

    /// <summary>
    /// Run the specified test method and return 
    /// Item1 = its status
    /// (<see cref="RunStatus.Passed"/>, etc.);
    /// Item2 = its name; and
    /// Item3 = any <see cref="Exception"/> that it raises,
    /// such as an <see cref="InconclusiveException"/> exception.
    /// </summary>
    /// <param name="testMethod">Test method to be run</param>
    /// <returns>{Item1 = status from running the test, Item2 = test method name,
    /// Item3 = Exception from test failure}</returns>
    internal static Tuple<RunStatus, string, Exception> RunTestMethod(Action testMethod)
    {
      const string listItemHdr = "";  //List item header
      var testStatus = RunStatus.Passed;

      var nameOfMethodBeingRun = testMethod.Method.Name;
      var displayName = listItemHdr +
              nameOfMethodBeingRun + "()";
      var declaringType = testMethod.Method.DeclaringType.FullName;  //...such as "TDS.Test"

      //Write the method's name in a format similar to what NUnit uses
      Console.WriteLine(TraceFlag
            + declaringType + "." + nameOfMethodBeingRun);

      Exception assertEx = null;  //Exception thrown, expected to be from an Assert statement.
      try
      {
        testMethod();
      }
      catch (InconclusiveException e)
      {
        testStatus = RunStatus.Inconclusive;
        assertEx = e;
      }
      catch (Exception e)  //Any exception except InconclusiveException, we assume, indicates failure
      {
        testStatus = RunStatus.Failed;
        assertEx = e;
      }

      return new Tuple<RunStatus, string, Exception>(testStatus, displayName, assertEx);

    }  // end:RunTestMethod()

    /// <summary>
    /// Static constructor for the Test{} class.
    /// This calls <see cref="InitializeClasses"/>().
    /// </summary>
    static Test()
    {
      Console.WriteLine(TraceFlag + "Test{} class's static constructor has been called.");

    }  // end: Test()

    /// <summary>
    /// Template for tests of methods that utilize the Console.  
    /// <para>The method actually called here is
    /// <see cref="TestableConsoleMethod"/>(), 
    /// but its only purpose is as a demonstration.</para>
    /// </summary>
    /// <remarks>
    /// <para>The test report should contain something like this:</para>
    /// <para> ---</para>
    /// <para> Beginning test of case #A1 One line of input</para>
    /// <para> " done</para>
    /// <para> ":</para>
    /// <para> Finished line 1, case #A1 One line of input:</para>
    /// <para>    Returned: "Returned: DONE"</para>
    /// <para>    To Console: "To the console: DONE</para>
    /// <para> "</para>
    /// <para> ---</para>
    /// <para> Beginning test of case #A2 Test throwing exception</para>
    /// <para> "I dislike</para>
    /// <para>    gnats, bedbugs, and mosquitoes.</para>
    /// <para> ":</para>
    /// <para> Finished line 1, case #A2 Test throwing exception:</para>
    /// <para>    Returned: "Returned: I DISLIKE"</para>
    /// <para>    To Console: "To the console: I DISLIKE</para>
    /// <para> "</para>
    /// <para> Finished line 2, case #A2 Test throwing exception:</para>
    /// <para>    Exception "Bugs are detected in this program." was correctly thrown.</para>
    /// <para> ---</para>
    /// <para> Beginning test of case #B1 Multiple input lines</para>
    /// <para> "  Say  hello</para>
    /// <para>  score</para>
    /// <para> ":</para>
    /// <para> Finished line 1, case #B1 Multiple input lines:</para>
    /// <para>    Returned: "Returned: SAY  HELLO"</para>
    /// <para>    To Console: "To the console: SAY  HELLO</para>
    /// <para> "</para>
    /// <para> Finished line 2, case #B1 Multiple input lines:</para>
    /// <para>    Returned: "Returned: SCORE"</para>
    /// <para>    To Console: "To the console: SCORE</para>
    /// <para> "</para>
    /// </remarks>
    [TestMethod]
    public static void TestableConsoleMethodTest()
    {
      #region testValues
      var testValues = new[] {
        #if(!UseNamedObjectTypeInTestableConsoleMethodTest)
        //These test case values are defined via
        //    anonymous object initializers, which is probably
        //    the most convenient way to define them when 
        //    only one or two instances are present.
        //  If more than one instance is present,
        //    comments describing the properties are needed
        //    only in or near the initializer of the first instance, though
        //    additional comments describing specific values might be useful.
        //
        //  Advantages: The type of each property need not be specified.
        //    All of the code defining an instance is located in one C# statement.
        //    No type name need appear, keeping the declaration short.
        //    No type definition is needed, keeping the program short.
        //  Disadvantages: Each property must be given an explicit value.
        //    Changes in the data structure must be applied identically to each instance.
        //    Properties must be declared in the same order in each instance.
        //    Comments on a property, or the type itself, are not visible in IntelliSense.
        
        new {
          // Test case identifier, consisting of unique 2-character tag,
          //    followed by a short verbal description
          Id = "A1 One line of input", 

          // String (possibly containing new-line characters)
          //    simulating the user's input from the keyboard
          InputLines = " done\r\n",

          // Output = expected output to the Console window.
          // Exception = exception expected to be thrown, if any.
          //   This specifies a string that is expected to match
          //   the beginning of the exception message.
          OutputExp = new[] {
              new{Output = "DONE", 
                Exception = ""},
            },
          },

        //Since more than one array element is defined here,
        //    and comments describing these objects' properties
        //    were supplied with the first instance in the array,
        //    comments describing the properties need not be repeated
        //    on these other instances.
        //  However, you may find it useful to apply comments to some
        //    of the specific values in the test cases.
        //    For example, a comment on the value given here for property "InputLines" 
        //    of this instance, "A2", is included with the property's value; 
        //    a comment describing the entire instance is contained 
        //    in the value of the instance's "Id" property; and 
        //    a comment describing what the "InputLines" property means for all instances
        //    is in or near the initializer for the first ("A1") instance.
        new {
          Id = "A2 Test throwing exception",
          InputLines = 
@"I dislike
   gnats, bedbugs, and mosquitoes.
",                                //This string includes the forbidden word!
          OutputExp = new[] {
            new{Output = "I DISLIKE", 
              Exception=""},
            new{Output = "", 
              Exception="Bugs are detected"},
            },
          },

        new {
          Id = "B1 Multiple input lines",
          InputLines = 
@"  Say  hello
  score
",
          OutputExp = new[] {
            new{Output = "SAY  HELLO", 
              Exception = ""},
            new{Output = "SCORE", 
              Exception = ""},
            },
          },

        #else  //#if (UseNamedObjectTypeInTestableConsoleMethodTest)
        //Note: These test case values are defined as
        //    objects of a named type, which is probably
        //    the most convenient way to define them when 
        //    many instances are present.
        //
        //  Advantages: Properties may be given default values.
        //    Changes in the data structure are easy to implement.
        //    Property values may appear in any desired order.
        //    Comments on each property, and on the type itself,
        //      including property types and default values,
        //      are visible in IntelliSense.
        //  Disadvantages: Property types must be explicitly specified.
        //    Some of the code defining the object is located in a remote part of the program.
        //    A type name must appear with each instance declaration, occupying space.
        //    The type must be explicitly declared somewhere in the namespace.

        new TestableConsoleMethodTestCase (Id : "A1 One line of input",
          InputLines : " done\r\n",
          OutputExp : new[] {
              new TestableConsoleMethodTestCaseOutputExp(
                Output : "DONE")
              }
          ),

        //This constructor's parameters can be defined to match 
        //    the object's properties.  They are documented in the constructor's
        //    XML comments and are visible in Visual Studio's IntelliSense.
        //  However, you may also find it useful to apply comments to some
        //    of the specific values in the test cases.
        //    For example, a comment on the value given here for property "InputLines" 
        //    of this instance, "A2", is included with the property's value; and
        //    a comment describing the entire instance is contained 
        //    in the value of the instance's "Id" property.
        new TestableConsoleMethodTestCase (
          Id: "A2 Test throwing exception",
          InputLines: 
@"I dislike
   gnats, bedbugs, and mosquitoes.
",                               //This string includes the forbidden word!
           OutputExp: new []{
             new TestableConsoleMethodTestCaseOutputExp(
               Output: "I DISLIKE"),
             new TestableConsoleMethodTestCaseOutputExp(
               Exception: "Bugs are detected"),
           }
          ),

        new TestableConsoleMethodTestCase ("B1 Multiple input lines",
          InputLines: 
@"  Say  hello
 score 
",
          OutputExp: new[] {
            new TestableConsoleMethodTestCaseOutputExp(
              Output: "SAY  HELLO"),
            new TestableConsoleMethodTestCaseOutputExp(
              Output: "SCORE"),
            }
          ),

        #endif  //(UseNamedObjectTypeInTestableConsoleMethodTest)
      };
      #endregion testValues

      var stdIn = Console.In;  //Used to restore the Console.
      var stdOut = Console.Out;

      try
      {
        if (IsUsingStandAloneTds) InitializeTestMethod();

        foreach (var tCase in testValues)
        {
          //Separate out the short identifying tag for this test case
          var caseId = tCase.Id.Substring(0, 2);

#if (RunOnlySelectedTestData)
          //Run only the test data sets specified here
          if (!new[] {
                "A2",
              }.Contains(caseId))
            continue;
#endif //RunOnlySelectedTestData

          Console.WriteLine(
                  @"
---
Beginning test of case #{0}
""{1}"":"
                  , tCase.Id  //{0}
                  , tCase.InputLines   //{1}
                );

          var sr = new StringReader(tCase.InputLines);
          Console.SetIn(sr);

          //Destination for output from the method to the Console
          var sBldr = new StringBuilder("");

          //# of input line within tCase.InputLines (first line is line 1)
          var lineNum = 0;

          //Read lines from the (simulated) Console one by one; stop at EOF
          while (sr.Peek() != -1)
          {
            ++lineNum;
            sBldr.Length = 0;  //Erase any previous output

            Console.SetOut(new StringWriter(sBldr));  //Capture what the method writes to the Console

            var exceptionThrown = "";
            var actual = "";

            try
            {
#if(UseNamedObjectTypeInTestableConsoleMethodTest)
              //Example of invoking an instance method to be tested.
              //   Construct an instance of the desired object, then invoke the method,
              //   as in the "instance.TestableConsoleMethodI()" expression here:
              var instance = new TestableConsoleMethodTestCase("00 New test case");
              actual = instance.TestableConsoleMethodI();  //Example instance-method call
#else
              //Example of invoking a static method, which returns a testable value
              //   and has a side effect (writing to the Console).
              actual = TDS.Testable.TestableConsoleMethod();
#endif  //(UseNamedObjectTypeInTestableConsoleMethodTest)

              //During TDS-style development, the purpose of the above statement is only
              //   to invoke a function member (in this case,
              //   the TestableConsoleMethod() method
              //   or instanceDef.TestableConsoleMethodI() method)
              //   while it is under development,
              //   and any returned value is unimportant.
              //After converting the TDS code to a test method,
              //   any returned values (and results of side effects,
              //   such as changes to the values of static fields)
              //   are available for use in Assert statements.

            }
            catch (Exception e)
            {
              exceptionThrown = e.Message;
            }

            Console.SetOut(stdOut);  //Resume writing to standard output

            if (exceptionThrown == "") exceptionThrown = DefaultExceptionMessage;
            var exceptionExp = tCase.OutputExp[lineNum - 1].Exception;
            if (exceptionExp == "") exceptionExp = DefaultExceptionMessage;

            Assert.IsTrue(
                  exceptionThrown.StartsWith(exceptionExp),
                  String.Format(
                    "Exception: Expected = starts with \"{0}\""
                      + "\r\n   Actual = {1}"
                    , exceptionExp  //{0}
                    , exceptionThrown  //{1}
                  ));

            if (exceptionThrown != DefaultExceptionMessage)
            {
              // Write progress info to the test report.
              // Note that the "Standard Console Output" in the test report
              //   does not contain what the Console wrote to sBldr.
              Console.WriteLine(
  @"Finished line {0}, case #{1}:
   Exception ""{2}"" was correctly thrown."
                      , lineNum  //{0}
                      , tCase.Id  //{1}
                      , exceptionThrown  //{2}
                   );

              //Ignore the remaining lines of this test case's inputs
              //   if any exception was thrown
              break;
            }
            Assert.AreEqual(
                  "Returned: " + tCase.OutputExp[lineNum - 1].Output,
                  actual,
                  String.Format(
                    "Returned value, case #{0}"
                    , tCase.Id  //{0}
                  ));

            //Even if the tested method does not return any values to its caller,
            // we can test what it writes to the Console.
            Assert.AreEqual(
                  "To the console: " + tCase.OutputExp[lineNum - 1].Output + "\r\n",
                  sBldr.ToString(),
                  "Value written to Console, case #" + tCase.Id);

            // Write progress info to the test report.
            // Note that the "Standard Console Output" in the test report
            //   does not contain what the Console wrote to sBldr.
            Console.WriteLine(
  @"Finished line {0}, case #{1}:
   Returned: ""{2}""
   To Console: ""{3}"""
                    , lineNum  //{0}
                    , tCase.Id  //{1}
                    , actual  //{2}
                    , sBldr.ToString()  //{3}
                  );
          }  // end:while(...)
        }  // end:foreach(...)

      }
      finally
      {
        Console.SetOut(stdOut);  //Restore the Console state
        Console.SetIn(stdIn);

        if (IsUsingStandAloneTds) CleanupTestMethod();
      }

      ////TODO: Remove the following statement after this [TestMethod] is working:
      Assert.Inconclusive("  Verify the correctness of this test method.");

    }  // end:TestableConsoleMethodTest()

#if(UseNamedObjectTypeInTestableConsoleMethodTest)
    /// <summary>
    /// This class is used in defining test cases
    /// for <see cref="TestableConsoleMethodTest"/>() .
    /// </summary>
    /// <remarks>
    /// <para>Using a constructor allows access to
    /// read-only properties and fields,
    /// and thus may be preferable to using an object initializer.</para>
    /// <para>To convert anonymous object initializers
    /// to named-type constructors, with properties
    /// to be replaced by same-named constructor parameters,</para>
    /// <para>- Include the type name.</para>
    /// <para>- Change braces to parentheses.</para>
    /// <para>- Change "=" to ":".</para>
    /// <para>- Delete a trailing comma, if present.</para>
    /// <para>For example, the following anonymous-object initializer:</para>
    /// <para>
    ///        new {Id = "01 Normal value"</para>
    /// <para>
    ///            , InputLines = "abc", </para>
    /// <para>
    ///          },</para>
    /// <para>may be replaced by the following constructor call,
    /// if the constructor is suitably defined:</para>
    /// <para>
    ///        new TestableConsoleMethodTestCase(Id : "01 Normal value"</para>
    /// <para>
    ///            , InputLines : "abc"</para>
    /// <para>
    ///          ),</para>
    /// <para>
    /// </para>
    /// <para>
    /// Comments in the anonymous object initializers that describe the properties 
    /// may be deleted, since they should have been copied
    /// to XML comments in the new type definition.  
    /// However, if the original initializers contained any
    /// comments that applied to specific values,
    /// it might be helpful to leave those comments in 
    /// the instance constructors, with the special values they describe.</para>
    /// <para>When you use this struct as a template,
    /// you will probably want to delete the code in the
    /// <c>#region MembersThatDoNotNeedToBeCopied</c> region
    /// (and make suitable changes to the constructor).</para>
    /// </remarks>
    internal struct TestableConsoleMethodTestCase
    {
      /// <summary>
      /// Test case identifier, consisting of unique 2-character tag,
      ///    followed by a short verbal description
      /// </summary>
      /// <remarks><para>This is useful in <c>Assert</c> statements
      /// to identify the failing test case.</para>
      /// <para>The 2-character tag is used,
      /// when <c>RunOnlySelectedTestData</c> is defined,
      /// to identify which test cases are to be run.
      /// </para>
      /// </remarks>
      internal readonly string Id;

      /// <summary>
      /// <para>Constructor with named arguments.</para>
      /// </summary>
      /// <param name="Id">Test case identifier (required),
      /// expected to contain a unique 2-character tag, a space,
      /// and a short verbal description.</param>
      /// <param name="ExpectedException">Message of exception expected to be thrown, if any.
      /// If the value is "No exception is thrown" (the default value),
      /// then the test case is expected not to cause an exception.</param>
      /// <param name="OutputExp">Expected output to the Console window.
      /// Default value is an array containing a single element with a value
      /// <para>new{Output = "", Exception = ""}.</para></param>
      /// <param name="InputLines">String (possibly containing new-line characters)
      ///    simulating the user's input from the keyboard</param>
      internal TestableConsoleMethodTestCase(
            string Id,
            string InputLines = "\r\n",
            TestableConsoleMethodTestCaseOutputExp[] OutputExp = null
            )
        : this()
      {
        this.Id = Id;
        this.InputLines = InputLines;
        this.OutputExp = OutputExp
              ?? new[] { 
                new TestableConsoleMethodTestCaseOutputExp(
                  Output: "", 
                  Exception: ""), };

      }  // end:TestableConsoleMethodTestCase()

    #region MembersThatDoNotNeedToBeCopied
      /// <summary>
      /// Message used to indicate that no exception was thrown
      /// </summary>
      const string DefaultExceptionMessage = Test.DefaultExceptionMessage;

      /// <summary>
      /// String (possibly containing new-line characters)
      ///    simulating the user's input from the keyboard
      /// </summary>
      /// <remarks>This could be defined instead as a readonly field;
      /// it's defined as a property here to serve as an illustration.</remarks>
      internal string InputLines { get; private set; }

      /// <summary>
      /// Example instance method that does nothing except
      /// to invoke static method <see cref="TestableConsoleMethod"/>()
      /// to read and write the <see cref="System.Console"/>.
      /// </summary>
      /// <returns>Same value returned by <see cref="TestableConsoleMethod"/>() .</returns>
      /// <remarks>This method is defined only in order to demonstrate
      /// the use of an instance method in the code.</remarks>
      internal string TestableConsoleMethodI()
      {
        return Testable.TestableConsoleMethod();
      }  // end:TestableConsoleMethodI()

      /// <summary>
      /// Expected output to the Console window
      /// </summary>
      internal readonly TestableConsoleMethodTestCaseOutputExp[] OutputExp;
    #endregion MembersThatDoNotNeedToBeCopied

    }  // end:TestableConsoleMethodTestCase{}

    /// <summary>
    /// This is used in specifying values of elements of <see cref="TestableConsoleMethodTestCase().OutputExp[]"/>
    /// </summary>
    internal struct TestableConsoleMethodTestCaseOutputExp
    {
      /// <summary>
      /// Exception expected to the thrown, if any.
      /// This specifies a string that is expected to match
      /// the beginning of the exception message.
      /// </summary>
      internal readonly string Exception;

      /// <summary>
      /// Expected output to the Console window
      /// </summary>
      internal readonly string Output;

      /// <summary>
      /// Constructor specifying expected response from one input line.
      /// </summary>
      /// <param name="Output">
      /// Expected output to the Console window
      /// </param>
      /// <param name="Exception">
      /// Exception expected to the thrown, if any
      /// </param>
      internal TestableConsoleMethodTestCaseOutputExp(string Output = "", string Exception = "")
        : this()
      {
        this.Output = Output;
        this.Exception = Exception;
      }

    } // end:TestableConsoleMethodTestCaseOutputExp{}
#endif //(UseNamedObjectTypeInTestableConsoleMethodTest)

    /// <summary>
    /// Template for tests of methods that do not utilize the Console.  
    /// <para>The method actually called here is <see cref="TestableNoConsoleMethod"/>(), 
    /// but its only purpose is as a demonstration.</para>
    /// </summary>
    /// <remarks>
    /// <para>This test method writes tracing information to the Console,
    /// for example via <see cref="InitializeTestMethod"/>(),
    /// to provide information for the test report.</para>
    /// </remarks>
    [TestMethod]
    public static void TestableNoConsoleMethodTest()
    {
      #region testValues
      var testValues = new[] {
        //Please see the comments in the definition of testValues
        //    in TestableConsoleMethodTest() for suggestions on defining
        //    the contents of testValues.

        new {
          Id = "01 Sample test", // Test case identifier, consisting of
                                 //   a unique 2-character tag,
                                 //   followed by a short verbal description
          Arg = 3,  // Input value
          ValueExp = 4,  // Expected returned value
        },

      };
      #endregion testValues

      try
      {
        if (IsUsingStandAloneTds) InitializeTestMethod();

        foreach (var tCase in testValues)
        {
          //Separate out the short identifying tag for this test case
          var caseId = tCase.Id.Substring(0, 2);

#if (RunOnlySelectedTestData)
          //Run only the test data sets specified here
          if (!new[] {
                "01",
              }.Contains(caseId))
            continue;
#endif //RunOnlySelectedTestData

          //Message value of an exception that the method to be called might throw
          var exceptionThrown = DefaultExceptionMessage;

          //Value returned by the method to be called
          var actual = 0;  //Give this some default value suitable to the method being tested.

          try
          {
            //Since TestableNoConsoleMethod() is an extension method,
            //    it may be called using instance-method syntax,
            //    so the following two statements yield the same result;
            //    choose one:
            actual = TDS.Testable.TestableNoConsoleMethod(tCase.Arg);
            actual = tCase.Arg.TestableNoConsoleMethod();
            //During TDS-style development, the purpose of the above statement is only
            //    to invoke the function member being developed (in this case,
            //    the TestableNoConsoleMethod() method)
            //    to facilitate observing the values of variables,
            //    and any returned values are relatively unimportant.

          }
          catch (Exception e)
          {
            exceptionThrown = e.Message;
          }

          //  After the new function member's code is complete enough
          //    to begin returning values to the TDS test method,
          //    these returned values (and the results of any side effects,
          //    such as changes to the values of static fields)
          //    are available for use in Assert statements,
          //    such as those appearing here:
          Assert.AreEqual(
                DefaultExceptionMessage,
                exceptionThrown,
                String.Format(
                  "TestableNoConsoleMethodTest(), test case {0}: An unexpected exception was thrown."
                  , tCase.Id  //{0}
                  )
                );

          Assert.AreEqual(
                tCase.ValueExp,
                actual,
                String.Format(
                  "TestableNoConsoleMethodTest(), test case {0}: Argument = {1}."
                  , tCase.Id  //{0}
                  , tCase.Arg  //{1}
                  )
                );
        }

      }
      finally
      {
        if (IsUsingStandAloneTds) CleanupTestMethod();
      }

      ////TODO: Remove the following statement after this [TestMethod] is working:
      Assert.Inconclusive("  Verify the correctness of this test method.");

    }  // end:TestableNoConsoleMethodTest()

    //==== New tests may be placed here:


  }  // end:Test{}

#endif //(DEBUG)

  /// <summary>
  /// This class contains example methods to be tested by
  /// example TDS methods in class <see cref="Test{}"/>.
  /// </summary>
  public static partial class Testable
  {

    /// <summary>
    /// Example method to be called by <see cref="TestableConsoleMethodTest"/>().
    /// <para>This reads a line of text from the Console, 
    /// trims and upper-cases it,</para>
    /// <para>writes to the Console that line preceded by "To the console: ",</para>
    /// <para>and returns to the caller the same line preceded by "Returned: ".</para>
    /// <para>Example:</para>
    /// <para>If the line read from the Console consists of the string "  done ",</para>
    /// <para>then this method writes to the Console "To the console: DONE"</para>
    /// <para>and returns to the caller the string "Returned: DONE".</para>
    /// </summary>
    /// <returns>"Returned: " + trimmed &amp; upper-cased line
    /// read from the Console.</returns>
    /// <exception cref="ApplicationException">Exception
    /// "Bugs are detected in this line."
    /// is raised if the word "BEDBUGS" appears anywhere in the input.</exception>
    public static string TestableConsoleMethod()
    {
      var nextLine = Console.ReadLine().Trim().ToUpper();

      if (nextLine.Contains("BEDBUGS"))
        throw new ApplicationException("Bugs are detected in this line.");

      Console.WriteLine(
              "To the console: {0}"
              , nextLine  //{0}
            );

      return string.Format(
              "Returned: {0}"
              , nextLine  //{0}
            );

    }  // end:TestableConsoleMethod()

    /// <summary>
    /// Example method to be called by <see cref="TestableNoConsoleMethodTest"/>().
    /// <para>This is an extension method,
    /// returning the value of its argument plus one.</para>
    /// <para>For example, (3).TestableNoConsoleMethod() = 4 .</para>
    /// </summary>
    /// <param name="param1">Integer value whose successor is to be returned.</param>
    /// <returns>Value of <paramref name="param1"/> plus 1.</returns>
    public static int TestableNoConsoleMethod(this int param1)
    {
      return ++param1;
    }  // end:TestableNoConsoleMethod()

  }  // end: Testable{}

}  // end: Namespace TDS

//TODO: The following example code may be used to simulate a project under development, to which TDS may be linked.
#if (Code_to_be_copied)
//The following code is intended to be copied into
//    Program{} or other classes containing code
//    under development, and not for use within TDS.Test{}.
//The conditional compilation symbol Code_to_be_copied
//    is not intended to be defined;
//    the "#if (Code_to_be_copied)" directive is intended
//    to hide these lines from the compiler.
//If the name of the calling class is not Program{},
//    change the name in these examples to match it,
//    and also update the contents of the Test.InitializeClasses() 
//    method in this file to include the correct name.

//Variable "isInitialized" is a new public static field that does nothing
//    except possibly to invoke the static constructor of its struct or
//    class (for example, to enable the test system to ensure
//    that the static fields are initialized).  A copy of this statement
//    may be inserted into Program{}, outside of Main(), and also
//    into any other class or struct that your code depends on.
//    This is needed only if no suitable static field or property
//    is already defined there; if you prefer to use such other variable,
//    modify the matching statement in InitializeClasses()
//    to refer to that variable instead.

      readonly static public bool isInitialized = true;
  
// If no static constructor is defined for one
//    or more class or struct definitions in your project,
//    one similar to the following may be inserted
//    into a suitable location in the definition.
//    This is not needed in a class or struct with no static members,
//    and you may wish to remove it or some of its contents
//    when you remove the TDS code from your completed project.

      static Program() {
        Console.WriteLine("***** Program{} class's static constructor has been called.");
      }  // end:Program()

//The following is new code that could be copied into the startup class's
//    Main() method or into its static constructor. 
//    This example includes a comment and a call to RunTdsTests() .
//Place this so that it will be executed following all code 
//    that initializes any variables used by the code to be tested.  
//    If necessary, change the "TDS.Test." in it to refer to 
//    the correct location of RunTdsTests().  
//    The "return" statement is intended to avoid accidentally running
//    the rest of Main() after calling the TDS code, but
//    you may find it useful to change the "return" statement 
//    to a "throw" or "goto" statement instead.
  
      TDS.Test.RunTdsTests(); return;

//An example Program{} class definition, illustrating suggested
//    placement of the needed components, follows.
//If you do copy this version of Program{} to a module to be run,
//    it should operate properly as written,
//    either with or without using the call to RunTdsTests().
//    However, since TDS.Test{} is intended to house 
//    the TDS methods that call function members developed elsewhere
//    but is not intended to contain those new function members themselves,
//    you can better simulate the organization of a real project by moving
//    both of those methods from the TDS.Testable{} class
//    to inside the ConsoleApplication1.Program{} class
//    (or to wherever you are planning to develop new code),
//    and update the references to them in the example Main() method
//    as well as in TestableNoConsoleMethodTest()
//    and TestableConsoleMethodTest() in the TDS.Test{} class.
//    Moving them there will allow you to de-couple your project from its
//    TDS code by commenting out the RunTdsTests() line and deleting the
//    project's reference to the TDS namespace.

/******Example Program{} class, illustrating placement of a TDS-related customizations,
 *     such as a call to RunTdsTests(), a new static field, and a new static constructor:

namespace ConsoleApplication1
{

  /// <summary>
  /// Example Program{} class
  /// </summary>
  /// <remarks>This example class is <c>static</c> only because
  /// it is intended to contain an extension method.
  /// <para>These XML comments may be viewed
  /// in Visual Studio's Object Browser.</para></remarks>
  public static class Program
  {

    /// <summary>
    /// Access this to run the static constructor 
    /// (if it hasn't been run already).
    /// </summary>
    readonly static public bool isInitialized = true;

    /// <summary>
    /// This calls <see cref="TestableNoConsoleMethod"/>
    /// and <see cref="TestableConsoleMethod"/>, writing
    /// their output to the Console.
    /// </summary>
    /// <exception cref="ApplicationException">
    /// may be raised, due to bugs.</exception>
    /// <param name="args">Command-line parameters</param>
    public static void Main(string[] args)
    {

      ////Setup instructions following the static constructor
      ////  might be placed here.
      Console.WriteLine("***** Program.Main() has begun running.");

#if(DEBUG)
      ////To run the Main() program normally instead of calling
      ////    the test methods, comment out or delete this code:
      TDS.Test.RunTdsTests(); return;
#endif //(DEBUG)

      ////The following code, currently unreachable,
      ////  is what would run if RunTdsTests() were not called.

      var three = 3;
      Console.WriteLine(@"
(This is a test of example method TestableNoConsoleMethod().)
    
  One plus {0} is {1}.
"
              , three  //{0}
              , TDS.Testable.TestableNoConsoleMethod(three)  //{1}
            );

      Console.WriteLine(@"
(This is a manual test of example method TestableConsoleMethod().)
    
  Type any words except ""bedbugs"", followed by <enter>.
    Do this twice.
");
      for (var n = 1; n <= 2; n++)
        TDS.Testable.TestableConsoleMethod();

    }  // end:Main()

    /// <summary>
    /// Example static constructor for the <c>Program{}</c> class.
    /// </summary>
    static Program()
    {
      Console.WriteLine("***** Program{} class's static constructor has been called.");
    }  // end:Program()

  }  // end:Program{}

}  // end:namespace ConsoleApplication1

******/////End of example Main() method

#endif //Code_to_be_copied

/**** Quick-start instructions *****
 * 
 * This code is intended to be used to call stubs of C# methods
 * and similar function members, providing a standardized way to
 * supply them with data for use in development and debugging.
 *   These TDS methods can also be adapted for use as unit tests,
 * compatible with NUnit and similar systems.
 * 
 * To see a quick demonstration, do the following:
 *   1) Install
 *        Microsoft .NET 4, 
 *        Visual Studio (Microsoft Visual C# 2010 Express or higher), and 
 *        NUnit (this code works with verion 2.5.8).
 *   2) In Visual Studio, create a new C# Console Application project
 *      and keep its default name of "ConsoleApplication1".
 *   3) Add existing items TDS.cs (this file) and
 *      TDS_Ex01.cs to the project.
 *   4) To this project, add references to the following NUnit DLLs:
 *        nunit.core.dll
 *        nunit.core.interfaces.dll
 *        nunit.framework.dll
 *   5) Use VS menu "File, Close Solution" and click "Save".
 *   6) Browse to a folder that does not contain a subfolder named "Demo".
 *   7) Set the Solution Name to "Demo"; click "Save".
 *   8) Rename the Demo\ folder if desired.
 *   9) Use VS menu "File, Open Project", 
 *      navigate to the possibly renamed folder, 
 *      open solution Demo.sln .
 *  10) In Program.cs, replace the contents of the 
 *      ConsoleApplication1{} namespace with the example code from
 *      the "#if (Code_to_be_copied)" region in file TDS.cs (this file).
 *  11) In VS menu "Project, ConsoleApplication1 Properties", 
 *      Application tab, set the Startup object to 
 *      ConsoleApplication1.Program{} .
 *  12) In the Build tab, check "Define DEBUG constant".
 *  13) Run the project, using VS menu "Debug, Start Without Debugging".
 *      The console output shoud include, near the end, the line
 *      "Passed: 1  Failed: 0  Inconclusive: 2"
 *  14) Run NUnit, creating a new NUnit project in folder Demo\ .
 *  15) Use NUnit menu "Project, Add Assembly" to add the newly built assembly
 *      Demo\ConsoleApplication1\bin\Release\ConsoleApplication1.exe
 *      to the NUnit project.
 *  16) Run the NUnit tests in this assembly; 
 *      the contents of its Text Output tab should resemble
 *      the beginning of the text that appeared in the Console window.
 *  17) In VS menu "Project, ConsoleApplication1 Properties", 
 *      in the Build tab, uncheck "Define DEBUG constant".
 *  18) Run the project, using VS menu "Debug, Start Without Debugging".
 *      This will illustrate running a project with TDS code removed;
 *      the Console window should appear, requesting some user input,
 *      and NUnit should no longer display any tests to be run.
 *  19) With DEBUG defined, use the //TODO: comments (see the Task List)
 *      as guides for customizing the TDS code.
 * 
 **** End of quick-start instructions *****/
